%{
#include "Interpreter.hpp"
%}

%union {
	int tokIndex;
	ShellCommand *command;
	SimpleShellCommand *simpleCommand;
	PipeCommand *pipeCommand;
	SequenceCommand *sequenceCommand;
	Redirection *redir;
}

%token <tokIndex> TOK_SEPARATOR
%token <tokIndex> TOK_TEXT
%token <tokIndex> TOK_LOCALIZED_TEXT
%token <tokIndex> TOK_COMMAND_SUBSTITUTE
%token <tokIndex> TOK_ARITH_SUBSTITUTE
%token <tokIndex> TOK_VAR
%token <tokIndex> TOK_PIPE
%token <tokIndex> TOK_PIPEPIPE
%token <tokIndex> TOK_AND
%token <tokIndex> TOK_ANDAND
%token <tokIndex> TOK_SEMICOLON
%token <tokIndex> TOK_NEWLINE
%token <tokIndex> TOK_EOF
%token <tokIndex> TOK_OPENPAREN
%token <tokIndex> TOK_CLOSEPAREN
%token <tokIndex> TOK_BANG
%token <tokIndex> TOK_GREATER
%token <tokIndex> TOK_LESS

%token <tokIndex> TOK_IF
%token <tokIndex> TOK_THEN
%token <tokIndex> TOK_ELSE
%token <tokIndex> TOK_ELIF
%token <tokIndex> TOK_FI

%start start

%locations
%parse-param {ParserContext *parseContext}
%lex-param {ParserContext *parseContext}
%pure-parser

%type <sequenceCommand> start
%type <sequenceCommand> statement_list
%type <sequenceCommand> command
%type <command> statement
%type <pipeCommand> pipeline
%type <simpleCommand> simple_command
%type <tokIndex> command_element
%type <tokIndex> text_element
%type <redir> redirection
%type <redir> redirection_file
%type <command> if_statement
%type <command> elif_clause

%left TOK_ANDAND
%left TOK_PIPEPIPE

%%

start:
	statement_list
		{ parseContext->result = $1; }
	;

statement_list:
	/*empty*/
		{ $$ = new SequenceCommand(); }
	| statement_list command_terminator
		{ $$ = $1; }
	| statement_list statement command_terminator
		{ $$ = $1;
		  if($2) $$->addCommand($2, SEQUENCE_SEMICOLON); }
	| statement_list statement TOK_AND command_terminator
		{ $$ = $1;
		  $$->setRunInBackground(true);
		  if($2) $$->addCommand($2, SEQUENCE_SEMICOLON); }
	;

statement:
	/*empty*/
		{ $$ = NULL; }
	| command
		{ $$ = $1; }
	| if_statement
		{ $$ = $1; }
	;

command:
	pipeline
		{ $$ = new SequenceCommand();
		  $$->addCommand($1, SEQUENCE_SEMICOLON); }
	| command TOK_ANDAND pipeline
		{ $$ = $1;
		  $$->addCommand($3, SEQUENCE_AND); }
	| command TOK_PIPEPIPE pipeline
		{ $$ = $1;
		  $$->addCommand($3, SEQUENCE_OR); }
	;

command_terminator:
	TOK_EOF
	| TOK_SEMICOLON
	| TOK_NEWLINE
	;

simple_command:
	command_element
		{ $$ = new SimpleShellCommand();
		  $$->addToken(parseContext->getToken($1)); }
	| simple_command command_element
		{ $$ = $1; $$->addToken(parseContext->getToken($2)); }
	| simple_command redirection
		{ $$ = $1; $$->addRedirection($2); }
	;

pipeline:
	simple_command
		{ $$ = new PipeCommand();
		  $$->addCommand($1); }
	| pipeline TOK_PIPE newline_list simple_command
		{ $$ = $1;
		  $$->addCommand($4); }
	;

redirection:
	TOK_GREATER opt_whitespace redirection_file
		{ $3->setType(REDIR_SENDTO);
		  $$ = $3; }
	| TOK_GREATER TOK_GREATER opt_whitespace redirection_file
		{ $4->setType(REDIR_APPENDTO);
		  $$ = $4; }
	| TOK_LESS opt_whitespace redirection_file
		{ $3->setType(REDIR_READFROM);
		  $$ = $3; }
	;

redirection_file:
	text_element
		{ $$ = new Redirection();
		  $$->addToken(parseContext->getToken($1)); }
	| redirection_file text_element
		{ $$ = $1;
		  $$->addToken(parseContext->getToken($2)); }
	;

if_statement:
	TOK_IF command command_terminator TOK_THEN statement_list TOK_FI
		{ $$ = new IfCommand($2, $5, NULL); }
	| TOK_IF command command_terminator TOK_THEN statement_list TOK_ELSE statement_list TOK_FI
		{ $$ = new IfCommand($2, $5, $7); }
	| TOK_IF command command_terminator TOK_THEN statement_list elif_clause TOK_FI
		{ $$ = new IfCommand($2, $5, $6); }
	;

elif_clause:
	TOK_ELIF command command_terminator TOK_THEN statement_list
		{ $$ = new IfCommand($2, $5, NULL); }
	| TOK_ELIF command command_terminator TOK_THEN statement_list TOK_ELSE statement_list
		{ $$ = new IfCommand($2, $5, $7); }
	| TOK_ELIF command command_terminator TOK_THEN statement_list elif_clause
		{ $$ = new IfCommand($2, $5, $6); }
	;

newline_list:
	| newline_list '\n'
	;

opt_whitespace:
	| opt_whitespace TOK_SEPARATOR
	| opt_whitespace TOK_NEWLINE
	;

command_element:
	text_element                    { $$ = $1; }
	| TOK_SEPARATOR                 { $$ = $1; }
	;

text_element:
	TOK_TEXT                        { $$ = $1; }
	| TOK_COMMAND_SUBSTITUTE        { $$ = $1; }
	| TOK_ARITH_SUBSTITUTE          { $$ = $1; }
	| TOK_VAR                       { $$ = $1; }
	;

